在浏览器环境下使用Protocol Buffers协议
什么是Protocol Buffers?
wiki上面有这样一段描述:
Protocol Buffers is a method of serializing structured data. It is useful in developing programs to communicate with each other over a wire or for storing data. The method involves an interface description language that describes the structure of some data and a program that generates source code from that description for generating or parsing a stream of bytes that represents the structured data.
它是一种序列化数据格式,类似我们常用的JSON,XML。用的比较多的是在后台服务间进行数据通讯。
概况:
基本流程
前端应该怎么使用?
在说怎么使用 Protocol Buffers 前先说一下具体涉及的几个概念:
- proto文件,用来定义需要的存储结构的文件。
- proto文件编译器,用来将在proto文件定义的存储结构转化成需要运行的开发语言环境版本,比如转换为JS环境下版本。
1. 编写proto文件
下面这个例子是都是比较简单常用的数据类型;也可自定义一些数据类型,比如下面的ClassType,这个类型可以用到协议文件的任何结构里面。
// common.proto
enum OSType{
type_mac = 1;
type_win = 2;
}
// msg.proto
import "common.proto";
enum ClassType{
type_one = 1;
type_second = 2;
}
message oneMsg {
required uint32 id = 1;
required string name = 2;
required ClassType type = 3;
optional OSType osType = 4;
}
更多的字段说明可以参考官方说明:https://developers.google.com/protocol-buffers/docs/proto
2. 选编译工具
goole官方工具 - google官方支持多语言,有一个统一的编译工具,不支持浏览器环境下的协议文件编译(也不建议这么做)。
protobuf.js - 第三方的一个针对JS环境的库
3. 编译proto文件(基于protobuf.js)
先install一下编译工具包
npm install protobufjs --save
使用编译工具把定义的proto文件编译成你想要的数据格式
# pbjs v6.7.0 参数格式 pbjs -t json -w es6 -o msg.js msg.proto common.proto #pbjs v4.1.2 参数格式 #pbjs -s proto -t json ./msg.proto > msg.json
具体参数可以参考:https://github.com/dcodeIO/protobuf.js#pbjs-for-javascript
常用的是JSON或者JS模块这两种模式;想直接使用proto文件?也是可以的,但是需要在生产环境引入protobuf.js的编译模块,并且性能会不如JS或者JSON这两种使用方式。
那JSON和JS模块这两个使用方式有什么区别?
本质上并没有任何区别!!!
但根据个人经验,如果用JSON的方式会更加可控,因为你可以选择性的使用这个JSON配置来在生产环境需要的时候再初始化协议相关工具函数。
4. 使用产出的JS工具函数处理数据
序列化
// 基于protobufjs v6.7.0 import * as $protobuf from "protobufjs/light"; // 基于protobufjs v4.1.2 //import * as $protobuf from "protobufjs"; import ProtoMsg from 'msg.json'; // 基于protobufjs v6.7.0 let Msg = (new $protobuf.Root()).addJSON(ProtoMsg); // 基于protobufjs v4.1.2 // let Msg = $protobuf.newBuilder({})["import"](ProtoMsg).build() Msg.encode({ id: 1, name: 'pb' type: 2 }); // <Buffer>
反序列化
// 基于protobufjs v6.7.0 import * as $protobuf from "protobufjs/light"; // 基于protobufjs v4.1.2 //import * as $protobuf from "protobufjs"; import ProtoMsg from 'msg.json'; // 基于protobufjs v6.7.0 let Msg = (new $protobuf.Root()).addJSON(ProtoMsg); // 基于protobufjs v4.1.2 // let Msg = $protobuf.newBuilder({})["import"](ProtoMsg).build() Msg.decode(<Buffer>) // === {id: 1,name: 'pb', type: 2}
###优势&劣势
####优势:
- 体积小, 相对XML和JSON,它表达同样的数据可以达到一个3到10倍的压缩效果。
- 序列化和反序列化性能高,因为二进制序列的操作效率会比字符串要高,并且Protocol Buffers没有类似xml的词法文法分析,序列化和反序列化的步骤少很多。
####劣势:
- 对于浏览器环境编译代码体积较大,因为预先加载数据的序列化和反序列化方法,会导致需要加载额外的js代码。
- 因为基于buffer,所以兼容性不如json和xml。
写在最后:
在前端实践Protocol Buffers的过程中我们遇到好些代码体积和组织的问题;如果你的页面跟server数据通讯非常频繁的话可以考虑使用Protocol Buffers,比如频繁即时通讯;如果是控制台或者其他一些spa应用,还是需要权衡一下数据使用成本,代码体积和数据压缩的收益。
相关参考资料: